/**
 * Friendly Interactive Recursion Educator (FIRE)
 * COMS 4115: Programming Languages & Translators
 * Prof. Aho
 * 
 * @author Brian Lu
 * @author Sahar Hasan
 * @author Steve Hehl
 * @author Tristan Naumann
 * @version 2009-05-12
 */
package firesymbols;

import java.util.*;

/**
 * A table of the standard functions for type checking.
 */
public class StandardFunctions {

    private Map<String,StandardFunctionSymbol> functions = new HashMap<String, StandardFunctionSymbol>(); // symbols in scope

    /**
     * Initialize all the functions on creation.
     * NOTE: This could be made singleton, but left for extensibility 
     */
    public StandardFunctions(){
    	
    	buildStandardFunctions(); 
    }
    
    private void buildStandardFunctions(){
    	
    	StandardFunctionSymbol s;
    	Symbol left, right, rtype;
    	
    	/**BINARY ARITHMETIC OPERATIONS**/
    	s = new StandardFunctionSymbol("aop");
    	
    	//<aop, int, int, int>
    	left = IntTypeSymbol.instance();
    	right = IntTypeSymbol.instance(); 
    	rtype = IntTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	

    	//<aop, float, float, float>
    	left = FloatTypeSymbol.instance();
    	right = FloatTypeSymbol.instance(); 
    	rtype = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	//<aop, float, int, float>
    	left = IntTypeSymbol.instance();
    	right = FloatTypeSymbol.instance(); 
    	rtype = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	
    	//<aop, float, float, int> 
    	left = FloatTypeSymbol.instance();
    	right = IntTypeSymbol.instance(); 
    	rtype = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	functions.put("aop", s);
    	
    	/**UNARY OPERATIONS**/
    	
    	//<uop, int, int> 
    	s = new StandardFunctionSymbol("uop");
    	left = IntTypeSymbol.instance();
    	rtype = IntTypeSymbol.instance();
    	s.addSignature(rtype, left);
    	
    	//<uop, float, float>
    	left = FloatTypeSymbol.instance();
    	rtype = FloatTypeSymbol.instance();
    	s.addSignature(rtype, left);

    	functions.put("uop", s);
    	
    	/**POWER OPERATION**/
    	s = new StandardFunctionSymbol("power");

    	//<power, float, float, float>
    	left = FloatTypeSymbol.instance();
    	right = FloatTypeSymbol.instance(); 
    	rtype = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	//<power, int, int, int>
    	left = FloatTypeSymbol.instance();
    	right = FloatTypeSymbol.instance(); 
    	rtype = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	//<power, float, int, float> 
    	left = IntTypeSymbol.instance();
    	right = FloatTypeSymbol.instance(); 
    	rtype = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
     	//<power, float, float, int> 
    	left = FloatTypeSymbol.instance();
    	right = IntTypeSymbol.instance(); 
    	rtype = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	functions.put("power", s);
    	
    	/**COMPARISIONS**/
    	s = new StandardFunctionSymbol("compare");
    	rtype = BoolTypeSymbol.instance(); 
     	
    	//<compare, bool, int, int> 
    	left = IntTypeSymbol.instance(); 
    	right = IntTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	  	
    	//<compare, bool, float, float>
    	left = FloatTypeSymbol.instance(); 
    	right = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	//<compare, bool, int, float>
    	left = IntTypeSymbol.instance(); 
    	right = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	//<compare, bool, float, int>
    	left = FloatTypeSymbol.instance(); 
    	right = IntTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    		
    	functions.put("compare", s);
    	

    	/**COMPARE EQ OPERATION**/ 
    	s = new StandardFunctionSymbol("compareeq");
    	rtype = BoolTypeSymbol.instance();
    	
    	//<compareq, bool, bool, bool> 
    	left = BoolTypeSymbol.instance();
    	right = BoolTypeSymbol.instance();
    	s.addSignature(rtype, left, right);
    	
    	//<compare, bool, int, int> 
    	left = IntTypeSymbol.instance(); 
    	right = IntTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	  	
    	//<compare, bool, float, float>
    	left = FloatTypeSymbol.instance(); 
    	right = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	//<compare, bool, int, float>
    	left = IntTypeSymbol.instance(); 
    	right = FloatTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	//<compare, bool, float, int>
    	left = FloatTypeSymbol.instance(); 
    	right = IntTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	functions.put("compareeq", s);
    	
    	/**BOOLEAN OPERATIONS**/
    	s = new StandardFunctionSymbol("bop");
    	
    	//<bop, bool, bool, bool> 
    	left = BoolTypeSymbol.instance();
    	right = BoolTypeSymbol.instance();
    	rtype = BoolTypeSymbol.instance(); 
    	s.addSignature(rtype, left, right);
    	
    	functions.put("bop", s);
    	
    	/**ASSIGNMENT OPERATIONS**/
    	 s = new StandardFunctionSymbol("assign");
   
    	 //<assign, int, int> 
    	 right = IntTypeSymbol.instance();
    	 rtype = IntTypeSymbol.instance(); 
    	 s.addSignature(rtype,rtype,right);
    	 
    	 //<assign, float, float> 
    	 right = FloatTypeSymbol.instance();
    	 rtype = FloatTypeSymbol.instance(); 
    	 s.addSignature(rtype, rtype, right);
    	 
    	 //<assign, float, int> 
    	 right = IntTypeSymbol.instance();
    	 rtype = FloatTypeSymbol.instance(); 
    	 s.addSignature(rtype, rtype, right);
    	 
    	 //<assign, bool, bool> 
    	 right = BoolTypeSymbol.instance();
    	 rtype = BoolTypeSymbol.instance(); 
    	 s.addSignature(rtype, rtype, right);
    	
    	 functions.put("assign", s);
    	 
    }
    
    /**
     * Lookup a signature list for a given name.
     * @param name the name of the standard function
     * @return 
     */
    public LinkedList<ArrayList<Symbol>> lookupSignatures(String name){
    	
    	LinkedList<ArrayList<Symbol>> signatures = functions.get(name).getSignatures();
    
    	return signatures;
    }
    
}
    
